#ifndef __MATCHER_H__
#define __MATCHER_H__
#include <list>
#include <mutex>
#include <condition_variable>
#include <thread>
#include "db.hpp"
#include "util.hpp"
#include "room.hpp"
#include "online.hpp"
template <class T>
class match_queue
{
public:
    int size()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        return _list.size();
    }
    bool empty()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        return _list.empty();
    }
    void wait()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _cond.wait(lock);
    }
    void push(const T& data)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _list.push_back(data);
        _cond.notify_all();
    }
    bool pop(T& data)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        if(_list.empty()) return false;
        data = _list.front();
        _list.pop_front();
        return true;
    }
    void remove(const T& data)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _list.remove(data);
    }
private:
    std::list<T> _list;
    std::mutex _mutex;
    std::condition_variable _cond;
};
class match_manager
{
private:
    void handle_match(match_queue<uint64_t>& mq)
    {
        while(1)
        {
            while(mq.size()<2)
            {
                mq.wait();
            }
            uint64_t uid1,uid2;
            bool ret = mq.pop(uid1);
            if(ret == false)
                continue;
            ret = mq.pop(uid2);
            if(ret == false)
            {
                this->add(uid1);
                continue;
            }
            wsserver_t::connection_ptr conn1 = _om->get_conn_from_hall(uid1);
            if(conn1.get() == nullptr)
            {
                this->add(uid2);
                continue;
            }
            wsserver_t::connection_ptr conn2 = _om->get_conn_from_hall(uid2);
            if(conn2.get() == nullptr)
            {
                this->add(uid1);
                continue;
            }
            room_ptr rp = _rm->create_room(uid1,uid2);
            if(rp.get() == nullptr)
            {
                this->add(uid1);
                this->add(uid2);
            }
            Json::Value resp;
            resp["optype"] = "match_success";
            resp["result"] = true;
            std::string body;
            Json_util::serialize(resp,body);
            conn1->send(body);
            conn2->send(body);
        }
    }
    void th_normal_enter()
    {
        handle_match(_q_normal);
    }
    void th_high_enter()
    {
        handle_match(_q_high);
    }
    void th_super_enter()
    {
        handle_match(_q_super);
    }
public:
    match_manager(user_table* ut,room_manager* rm,online_manager* om)
    :_ut(ut)
    ,_rm(rm)
    ,_om(om)
    ,_th_normal(std::thread(&match_manager::th_normal_enter,this))
    ,_th_high(std::thread(&match_manager::th_high_enter,this))
    ,_th_super(std::thread(&match_manager::th_super_enter,this))
    {
        ILOG("匹配管理创建成功");
    }
    bool add(uint64_t uid)
    {
        Json::Value user;
        bool n = _ut->select_id(user,uid);
        if(n==false)
        {
            ELOG("获取用户信息失败");
            return false;
        }
        int source = user["source"].asInt();
        if(source<2000)
            _q_normal.push(uid);
        else if(source>=2000&&source<3000)
            _q_high.push(uid);
        else
            _q_super.push(uid);
        return true;
    }
    bool del(uint64_t uid)
    {
               Json::Value user;
        bool n = _ut->select_id(user,uid);
        if(n==false)
        {
            ELOG("获取用户信息失败");
            return false;
        }
        int source = user["source"].asInt();
        if(source<2000)
            _q_normal.remove(uid);
        else if(source>=2000&&source<3000)
            _q_high.remove(uid);
        else
            _q_super.remove(uid);
        return true;
    }
    ~match_manager()
    {}
private:
    match_queue<uint64_t> _q_normal;
    match_queue<uint64_t> _q_high;
    match_queue<uint64_t> _q_super;
    std::thread _th_normal;
    std::thread _th_high;
    std::thread _th_super;
    user_table* _ut;
    room_manager* _rm;
    online_manager* _om;
};
#endif